#include "gamefunc.h"

MouseData* rpacote;

extern int byte1;
extern int byte2;
extern int byte3;

extern int completo;

// variaveis info mouse
Byte MSBy1 = 0;
Byte MSBy2 = 0;
Byte MSBy3 = 0;
int dx = 0;
int dy = 0;
int xov = 0;
int yov = 0;
int lmb = 0;
int mmb = 0;
int rmb = 0;


int x_pos=50, y_pos=200;

void GetInput(){
	extern Game game;
	extern ConfigInfo conf;
	extern Queue keys_queue;
	extern GQueue* mouse_queue;
	extern int last_sc;
	mask_pic(KBD_IRQ);
	if(!queueEmpty(&keys_queue))
	{
		last_sc = queueGet(&keys_queue);
		if(last_sc == conf.leftKey){
			game.hero.dx=-10;
		}else if(last_sc == (conf.leftKey|0x80)){
				game.hero.dx=0;
		}
		if(last_sc == conf.rightKey){
			game.hero.dx=10;
		}else if(last_sc == (conf.rightKey|0x80)){
			game.hero.dx=0;
		}
		if(last_sc == conf.jumpKey){
			if(!game.hero.jumpBegin)
				game.hero.jump = 1;
		}
	}
	unmask_pic(KBD_IRQ);
	mask_pic(MOUSE_IRQ);
	if(!isEmptyGQueue(mouse_queue))
	{
		parse_mouse_event();
		process_mouse_event();
	}
	unmask_pic(MOUSE_IRQ);
}


int Update(Level *level){
	extern Game game;
	extern ConfigInfo conf;
	if(level->enemy.alive){
		if(!level->enemy.isMonster)
			moveEnemy( &(level->enemy) , game.hero);
		else moveMonster(&(level->enemy));
	}
	
	if(!isPlatformBelow(game.hero , level->bgCollision->map)){
		game.gravity = 1;
		game.hero.jumpBegin = 1;
	}else{
		game.gravity = 0;
	}
	
	if(game.hero.jump){
		game.hero.vSpeed = -25;
		game.hero.jump=0;
		game.hero.jumpBegin=1;
		game.hero.temp_y = game.hero.sprite->y;
	}
	
	if(game.hero.jumpBegin || game.gravity){
		game.hero.vSpeed = game.hero.vSpeed + game.gravity;
		if(game.hero.vSpeed > 5)
			game.hero.vSpeed = 5;
		game.hero.temp_y = game.hero.temp_y + game.hero.vSpeed;
	}
	
	if(game.hero.temp_y<0) game.hero.temp_y=0;
	if(game.hero.temp_y>VRES) game.hero.temp_y=VRES;
	
	
	
	if(isPlatformAbove(game.hero , level->bgCollision->map)){
		game.hero.vSpeed = 0;
	}
	
	game.hero.sprite->y = game.hero.temp_y;
	
	if(isPlatformBelow(game.hero , level->bgCollision->map)){
		game.hero.jumpBegin=0;
	}
	//TODO verificar que nao passa do ecra horizontalmente
	game.hero.sprite->x += game.hero.dx;
	if(isColidingFloor(game.hero , level->bgCollision->map)){
		game.hero.sprite->x -= game.hero.dx;
	}
	if(game.hero.sprite->x <0) game.hero.sprite->x =0;
	if(game.hero.sprite->x + game.hero.sprite->width >HRES) game.hero.sprite->x = HRES - game.hero.sprite->width;
	
	if(game.hero.blinking){
		game.hero.blinktime--;
	}
	
	if(game.hero.blinktime == 0){
		game.hero.blinking = false;
		game.hero.blinktime = RECOVERY_TIME;
	}
	
	if(rmb && !game.hero.shootingBegin){
		game.hero.shootingBegin = true;
		game.hero.stone.exist = true;
		game.hero.stone.sprite->x = game.hero.sprite->x;
		game.hero.stone.sprite->y = game.hero.sprite->y;
		game.hero.stone.xFinal = x_pos;
		game.hero.stone.yFinal = y_pos;
		game.hero.stone.xInit = game.hero.sprite->x;
		game.hero.stone.yInit = game.hero.sprite->y;
		int a,b;
		
		///////////////////////////////////////////// STONE MOVES ////////
		int x0,x1,y0,y1;
		
		
		x0 = game.hero.stone.sprite->x;
		y0 = game.hero.stone.sprite->y;
		x1 = game.hero.stone.xFinal;
		y1 = game.hero.stone.yFinal;
		
		a = abs(x1 - x0);
		b = abs(y1 - y0);
		
		if(y1>y0){
			game.hero.stone.ySpeed = map(b,0,VRES,MAP_RATIO_MINY,MAP_RATIO_MAXY);
		} else {
			game.hero.stone.ySpeed = -1*map(b,0,VRES,MAP_RATIO_MINY,MAP_RATIO_MAXY);
		}
		if(x1>x0){
			game.hero.stone.xSpeed = map(a,0,HRES,MAP_RATIO_MINX,MAP_RATIO_MAXX);
		}else {
			game.hero.stone.xSpeed = -1*map(a,0,HRES,MAP_RATIO_MINX,MAP_RATIO_MAXX);
		}
		
	
	}
	
	if(game.hero.stone.exist 
		&& !isStoneCollidingBg(game.hero.stone,level->bgCollision->map)){
		moveStone(&(game.hero.stone));
		if(isStoneCollidingEnemy(game.hero.stone,level->enemy)
			&& level->enemy.alive && !level->enemy.isMonster){
			level->enemy.alive = false;
			game.hero.score += 50;
			game.hero.shootingBegin = false;
			game.hero.stone.exist = false;
		}else if(level->enemy.isMonster){
			if(level->enemy.lives>0){
				level->enemy.lives--;
				game.hero.score+=100;
				game.hero.shootingBegin = false;
				game.hero.stone.exist = false;
			}else if(level->enemy.lives<0){
				level->enemy.alive = false;
				game.hero.score += 50;
				game.hero.shootingBegin = false;
				game.hero.stone.exist = false;
			}
		}
	}else if(isStoneCollidingBg(game.hero.stone,level->bgCollision->map)){
		game.hero.shootingBegin = false;
		game.hero.stone.exist = false;
	}
	
	if(!game.hero.blinking 
		&& level->enemy.alive 
		&& isColidingEnemy(game.hero , level->enemy)){
		if(game.hero.lives!=1){
			game.hero.lives-=1;
			game.hero.blinking=true;
		}else{ //perdeu o nivel
			return 0;
		}
	}
	
	//uptade time
	actualTime(&conf);
	
	if(isEmptyGQueue(conf.music_queue)){
		initializeMusic(level->songNumber);
	}
	return 1;
}

void Draw(Level level){
	extern Game game;
	extern ConfigInfo conf;
	extern char* double_buffer;
	
	memcpy(double_buffer,level.background->map,HRES*VRES);
	displayLives();
	draw_sprite(game.hero.sight,double_buffer);
	if(game.hero.stone.exist)
		draw_sprite(game.hero.stone.sprite,double_buffer);
	draw_sprite(game.hero.sprite, double_buffer);
	if(level.enemy.alive)
		draw_sprite(level.enemy.sprite, double_buffer);
		
	
	//draw actual time
	drawStringAt("Tempo:", 0, 5, 16, 0, 2, double_buffer, conf.table);
	drawIntAt(conf.secActual, 96, 5, 16, 0, 2,double_buffer, conf.table);
	//draw score
	drawStringAt("Pontuacao:", 164,5,16,0,2,double_buffer,conf.table);
	drawIntAt(game.hero.score,320,5,16,0,2,double_buffer,conf.table);
	
   
	
	while ((inportb(INPUT_STATUS_1) & VRETRACE));
		while (!(inportb(INPUT_STATUS_1) & VRETRACE));
			memcpy(conf.video_base,double_buffer,HRES*VRES);
}

void displayLives(){
	extern Game game;
	extern char* double_buffer;
	disable();
	if(game.hero.lives == 3){
		draw_sprite(game.liveSprite,double_buffer);
		game.liveSprite->x -= game.liveSprite->width + 5;
		draw_sprite(game.liveSprite,double_buffer);
		game.liveSprite->x -= game.liveSprite->width + 5;
		draw_sprite(game.liveSprite,double_buffer);
		game.liveSprite->x = HRES - game.liveSprite->width - 5;
	}else if(game.hero.lives == 2){
		draw_sprite(game.liveSprite,double_buffer);
		game.liveSprite->x -= game.liveSprite->width + 5;
		draw_sprite(game.liveSprite,double_buffer);
		game.liveSprite->x = HRES - game.liveSprite->width - 5;
	}else if(game.hero.lives == 1){
		draw_sprite(game.liveSprite,double_buffer);
		game.liveSprite->x = HRES - game.liveSprite->width - 5;
	}
	enable();
}

void moveEnemy(Enemy *enemy, Hero hero){	
	if(enemy->sprite->x > hero.sprite->x){
		enemy->dumbr=DUMBNESS_L1;
		if(enemy->dumbl==0){
			enemy->sprite->x -= 2;
		}else{
			enemy->dumbl--;
			if(enemy->dumbl==0){
				int old_x = enemy->sprite->x;
				int old_y = enemy->sprite->y;
				disable();
				destroy_sprite(enemy->sprite);
				enemy->sprite = create_sprite(mouseSmallToLeft_xpm);
				enable();
				enemy->sprite->x=old_x;
				enemy->sprite->y=old_y;
			}
		}
	}
	if(enemy->sprite->x < hero.sprite->x){
		enemy->dumbl=DUMBNESS_L1;
		if(enemy->dumbr==0){
			enemy->sprite->x += 2;
		}else{
			enemy->dumbr--;
			if(enemy->dumbr==0){
				int old_x = enemy->sprite->x;
				int old_y = enemy->sprite->y;
				disable();
				destroy_sprite(enemy->sprite);
				enemy->sprite = create_sprite(mouseSmallToRight_xpm);
				enable();
				enemy->sprite->x = old_x;
				enemy->sprite->y = old_y;
			}
		}
	}		
}

void moveMonster(Enemy *enemy){	
	enemy->sprite->x += enemy->direction * MONSTER_XSPEED;
	int x = enemy->sprite->x;
	if(x > 200 && x < 400 - (enemy->sprite->width / 2)){
			if(enemy->direction == RIGHT_DIRECTION)
				enemy->sprite->y += MONSTER_YSPEED;
			else enemy->sprite->y -= MONSTER_YSPEED;
	}	else if(x >= 400 && x < 600 - (enemy->sprite->width / 2)) {
			if(enemy->direction == RIGHT_DIRECTION) 
				enemy->sprite->y -= MONSTER_YSPEED;
			else enemy->sprite->y += MONSTER_YSPEED;
	} else if(x <= 0){
		enemy->direction = RIGHT_DIRECTION; 
	} else if(x + enemy->sprite->width >= HRES){
		enemy->direction = LEFT_DIRECTION;
	}
}

void moveStone(Stone* stone){
	extern Game game;
	if(stone->sprite->x < 0 || (stone->sprite->x + stone->sprite->width) > HRES ||
		stone->sprite->y < 0 || (stone->sprite->y + stone->sprite->height) > VRES){
		stone->exist = false;
		game.hero.shootingBegin = false;
	}else{
		stone->sprite->x += stone->xSpeed;
		stone->sprite->y += stone->ySpeed;
		//movimento para a direita
		if(stone->xSpeed > 0){
			if(stone->xSpeed > MIN_XSPEED)
				stone->xSpeed--;
		}	else{ //movimento para a esquerda
			if(abs(stone->xSpeed) > MIN_XSPEED)
				stone->xSpeed++;
		}
		if(stone->ySpeed > MIN_YSPEED){
			stone->ySpeed = MIN_YSPEED;
		}
		else stone->ySpeed++;
	}
}

void parse_mouse_event()
{	
	extern GQueue * mouse_queue;
	//para ficar apenas com a ultima leitura
	while(!isEmptyGQueue(mouse_queue)){
		rpacote = (MouseData*)getGQueue(mouse_queue);
	}
	
	MSBy1 = rpacote->Byte1;
	MSBy2 = rpacote->Byte2;
	MSBy3 = rpacote->Byte3;
	if (MSBy1 & XSGN)
		dx = (MSBy2 - 256);
	else
		dx = MSBy2;
	if (MSBy1 & YSGN)
		dy = (MSBy3 - 256);
	else		
		dy = MSBy3;
	xov = X_OVERFLOW(MSBy1);
	yov = Y_OVERFLOW(MSBy1);
	lmb = LEFT_BUTTON(MSBy1);
	mmb = MIDDLE_BUTTON(MSBy1);
	rmb = RIGHT_BUTTON(MSBy1);
}

void process_mouse_event()
{
	extern Game game;
	x_pos += dx;
	y_pos -= dy;
	
	if (x_pos < 0)
		x_pos = 0;
	else if(x_pos >= HRES)
			x_pos = HRES -1;
			
	if (y_pos < 0)
		y_pos = 0;
	else if(y_pos >= VRES)
			y_pos = VRES -1;
			
	game.hero.sight->x = x_pos;
	game.hero.sight->y = y_pos;
}
